<script setup>
import { defineExpose, onMounted, ref } from 'vue'
import { area, layerInfo } from "@/utils/api.js"
import olMap from "ol/Map";
import View from "ol/View";
import * as olProj from "ol/proj";
import { Vector as VectorSource, XYZ } from "ol/source";
import { Tile as TileLayer, Image as ImageLayer, Vector as VectorLayer } from "ol/layer";
import { defaults as defaultControls, OverviewMap } from 'ol/control';
import ImageWMS from 'ol/source/ImageWMS';
import { Circle as CircleStyle, Fill, Stroke, Style, Text, Icon } from 'ol/style';
import GeoJSON from "ol/format/GeoJSON";
import Overlay from "ol/Overlay";
import Draw from "ol/interaction/Draw";
import Feature from "ol/Feature";
import { Polygon } from "ol/geom";
import close from '@/assets/icon/close.svg';
const emit = defineEmits(['PopUp', 'send', 'geometryDraw'])

import l1 from '@/assets/icon/l1.png'
import l2 from '@/assets/icon/l2.png'

let closer = null;
let container = null;
let PopOverlay = null;
import "ol/ol.css";

let areaId = '';
const base = ref([]);
const other = ref([]);
const lw = ref(0)
const radio = ref('天地图');
const checkList = ref([]);
let map = null;
let totalMap = {};
let vectorSource = null;
/* B 绘制相关变量 */
let drawLayer = null; // 绘制图层，用于显示所有绘制的几何图形
let drawSource = null; // 绘制图层的源
let currentDraw = null; // 当前绘制的交互对象
/* E */

const SwitchLayers = (data) => {
  if (lw.value == data) {
    lw.value = 0;
  } else {
    lw.value = data;
  }
}

const getarea = async () => {
  let res = await area(areaId)
  if (res) {
    let d = res.data.mapConfig;
    init(d.lon, d.lat, d.level);

  }
}

const getlayerInfo = async () => {
  let params = {
    areaId: areaId,
    userId: ""
  }
  let res = await layerInfo(params)
  if (res.code == '200') {
    base.value = res.data.base;
    base.value.forEach(e => {
      if (e.name === '天地图') {
        addXYZ('baseLayer', e.layerUrl)
      }
    })
    other.value = res.data.other;
    other.value.forEach(e => {
      if (e.selected) {
        drawWMS(e.id, e.layerUrl, e.layerName, e.styleId, e.cql);
        checkList.value.push(e.name)
      }
    })
  }
}

const init = (lon, lat, level) => {
  let center = [lon, lat]; // 地图的初始中心点
  container = document.getElementById('popup');
  closer = document.getElementById('popup-closer');
  PopOverlay = new Overlay({
    element: container,
    autoPan: {
      animation: {
        duration: 250,
      },
    },
  });
  map = new olMap({
    target: 'map',
    layers: [],
    overlays: [PopOverlay],
    controls: defaultControls({
      attribution: false,
      zoom: false,
      rotate: false
    }).extend([new OverviewMap()]),
    view: new View({
      //设置中心点
      center: olProj.fromLonLat(center),
      zoom: 11,
    })
  });

  getlayerInfo();

  // map.on('singleclick', function (evt) {
  //   let feature = map.forEachFeatureAtPixel(evt.pixel,
  //     function (feature) {
  //       return feature;
  //     });
  //   var coordinate = olProj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326');
  //   emit('send', coordinate)
  // });

  /* B 初始化绘制图层 */
  initDrawLayer();
  /* E */
};

const addXYZ = (item, url) => {
  if (typeof (totalMap[item]) != "undefined") {
    map.removeLayer(totalMap[item]);
    delete totalMap[item];
  }
  totalMap[item] = new TileLayer({
    source: new XYZ({
      url: url
    })
  },
  )
  map.addLayer(totalMap[item])
};

//绘制wms类型
const drawWMS = (item, url, name, styleId, cql) => {
  if (typeof (totalMap[item]) != "undefined") {
    map.removeLayer(totalMap[item]);
    delete totalMap[item];
  } else {
    let params = {
      'LAYERS': name,
      'STYLES': styleId,
      'CQL_FILTER': "[" + cql + "]"
    };

    totalMap[item] = new ImageLayer({
      source: new ImageWMS({
        url: url,
        params: params,
        serverType: 'geoserver'
      })
    })
    map.addLayer(totalMap[item]);
  }
};

const previewshape = (data, id) => {
  //判断是否已经存在相同id的图层 如果有删掉，再重新绘制
  if (typeof (totalMap[id]) != "undefined") {
    map.removeLayer(totalMap[id]);
    delete totalMap[id];
  }
  let styleFunction = function () {
    return function (feature, resolution) {
      //点
      if (feature.getGeometry().getType() == 'Point') {
        if (feature.get('fillColor').indexOf('#') != -1) {
          var point = new Style({
            image: new CircleStyle({
              radius: feature.get("radius"),
              fill: new Fill({
                color: feature.get("fillColor")
              }),
              stroke: new Stroke({
                color: feature.get("borderColor"),
                width: feature.get("size")
              })
            }),
            text: new Text({
              font: '16px Microsoft YaHei',
              text: feature.get('name'),
              fill: new Fill({
                color: '#fff'
              }),
              offsetY: 15,
              stroke: new Stroke({
                color: '#4C4ADD',
                width: 1
              }),
            })
          })
        } else {
          var point = new Style({
            image: addImage(feature, resolution),
            text: new Text({
              font: '16px Microsoft YaHei',
              text: feature.get('name'),
              fill: new Fill({
                color: '#fff'
              }),
              offsetY: 15,
              stroke: new Stroke({
                color: '#4C4ADD',
                width: 1
              }),
            })
          })
        }
        return [point]
      }
      if (feature.getGeometry().getType() == 'MultiPoint') {
        var MultiPoint = new Style({
          image: new CircleStyle({
            radius: 5,
            fill: new Fill({
              color: feature.get("fillColor")
            }),
            stroke: new Stroke({
              color: feature.get("borderColor"),
              width: feature.get("size")
            })
          }),
          text: new Text({
            font: '12px Calibri,sans-serif',
            text: feature.get('text'),
            fill: new Fill({
              color: feature.get('fillColor')
            }),
            offsetY: 15,
            stroke: new Stroke({
              color: 'white',
              width: 1
            }),
          })
        })
        return [MultiPoint]
      }
      //面
      if (feature.getGeometry().getType() == 'MultiPolygon') {
        var MultiPolygon = new Style({
          stroke: new Stroke({
            color: feature.get('borderColor'),
            width: feature.get("size")
          }),
          fill: new Fill({
            color: feature.get("fillColor")
          }),
          text: new Text({
            font: '16px Calibri,sans-serif',
            text: feature.get('text'),
            fill: new Fill({
              color: feature.get('textColor')
            }),
            stroke: new Stroke({
              color: feature.get('textColor'),
              width: 1
            })
          })
        })
        return [MultiPolygon]
      }
      if (feature.getGeometry().getType() == 'Polygon') {
        var Polygon = new Style({
          stroke: new Stroke({
            color: feature.get('borderColor'),
            width: feature.get("size")
          }),
          fill: new Fill({
            color: feature.get("fillColor")
          }),
          text: new Text({
            font: '12px Calibri,sans-serif',
            text: feature.get('text'),
            fill: new Fill({
              color: feature.get('borderColor')
            }),
            stroke: new Stroke({
              color: 'white',
              width: 3
            }),
          })
        })
        return [Polygon]
      }
      //线
      if (feature.getGeometry().getType() == 'LineString') {
        var LineString = new Style({
          stroke: new Stroke({
            color: feature.get('borderColor'),
            width: 2
          }),
          fill: new Fill({
            color: feature.get("fillColor"),
            width: 2
          }),
          text: new Text({
            font: '12px Calibri,sans-serif',
            text: feature.get('text'),
            fill: new Fill({
              color: 'white'
            }),
            stroke: new Stroke({
              color: 'block',
              width: 2
            }),
          })
        })
        return [LineString]
      }
      //多线
      if (feature.getGeometry().getType() == 'MultiLineString') {
        var MultiLineString = new Style({
          stroke: new Stroke({
            color: feature.get('borderColor'),
            width: feature.get("size") + 3
          }),
          text: new Text({
            font: '12px Calibri,sans-serif',
            text: feature.get('text'),
            fill: new Fill({
              color: 'white'
            }),
            stroke: new Stroke({
              color: 'block',
              width: 2
            }),
          })
        })
        return [MultiLineString]
      }
    }
  };
  let geojsonObject = {
    'type': 'FeatureCollection',
    'crs': {
      'type': 'name',
      'properties': {
        'name': 'EPSG:4326'
      }
    },
    'features': []
  };
  vectorSource = new VectorSource({
    features: (new GeoJSON(
      {
        defaultDataProjection: 'EPSG:4326',
        featureProjection: 'EPSG:3857'
      }
    )).readFeatures(geojsonObject)
  });
  totalMap[id] = new VectorLayer({
    source: vectorSource,
    style: styleFunction()
  });
  let sources = totalMap[id].getSource();
  data.forEach((e => {
    sources.addFeatures(
      (new GeoJSON({
        defaultDataProjection: 'EPSG:4326',
        featureProjection: 'EPSG:3857'
      })).readFeatures({
        "id": e.id,
        "properties": {
          "name": e.name,
          "borderColor": e.borderColor,
          "fillColor": e.fillColor,
          "iconSrc": e.iconSrc,
          "data": e.data
        },
        'type': 'Feature',
        'geometry': e.geojson
      }))
  }));
  totalMap[id].set("altitudeMode", "clampToGround");
  map.addLayer(totalMap[id]);
  totalMap[id].setZIndex(99)
  // let centerid = data[0].id,
  //     thisfeature = vectorSource.getFeatureById(centerid),
  //     center = thisfeature.getGeometry().getFirstCoordinate();
  // map.getView().setCenter(center);
};
//点类型绘制图标 需要定位图标位置
//地图图标位置处理函数
const addImage = (feature, resolution) => {
  let src = feature.get('iconSrc');
  let anchor = [0, 1];
  //根据图标文件名 设置定位点  地图上放置的图标更改文件名即可保持一致
  if (src != '') {
    if (src.indexOf('anchor_bottom_center') != -1) {
      anchor = [0.5, 1];
    } else if (src.indexOf('anchor_bottom_left') != -1) {
      anchor = [0, 1];
    } else if (src.indexOf('anchor_bottom_right') != -1) {
      anchor = [1, 1];
    } else if (src.indexOf('anchor_center_center') != -1) {
      anchor = [0.5, 0.5];
    } else if (src.indexOf('anchor_top_center') != -1) {
      anchor = [0.5, 0];
    } else if (src.indexOf('anchor_top_left') != -1) {
      anchor = [0, 0];
    } else if (src.indexOf('anchor_top_right') != -1) {
      anchor = [1, 0];
    }
    return new Icon({
      src: feature.get('iconSrc'),
      anchor: [0.5, 1],
      scale: 0.5
    });
  }
};

const locationM = (center) => {
  map.getView().setCenter(olProj.fromLonLat(center));
  map.getView().setZoom(18);
}

const delIlayer = (item) => {
  if (typeof (totalMap[item]) != "undefined") {
    map.removeLayer(totalMap[item]);
    delete totalMap[item];
  }
}

/* B ============================================ 绘制功能相关方法 ============================================ */

/**
 * 初始化绘制图层
 * 创建一个独立的VectorLayer用于显示所有绘制的几何图形
 * 该图层与previewshape使用的图层分开管理，避免冲突
 */
const initDrawLayer = () => {
  drawSource = new VectorSource({ wrapX: false });
  drawLayer = new VectorLayer({
    source: drawSource,
    style: getDrawStyle() // 使用统一的绘制样式
  });
  map.addLayer(drawLayer);
  drawLayer.setZIndex(100); // 设置较高的z-index，确保绘制图层在最上层
}

/**
 * 获取绘制样式函数
 * 根据不同的几何类型返回对应的样式
 * @returns {Function} 样式函数
 */
const getDrawStyle = () => {
  const createLabel = (feature, options = {}) => {
    const name = feature.get('name') || '';
    if (!name) {
      return undefined;
    }
    return new Text({
      text: name,
      font: '14px Microsoft YaHei',
      fill: new Fill({
        color: '#ffffff'
      }),
      stroke: new Stroke({
        color: 'rgba(0, 0, 0, 0.7)',
        width: 3
      }),
      ...options
    });
  };

  return (feature) => {
    const geometryType = feature.getGeometry().getType();
    let style = null;

    /* B 根据几何类型设置不同的样式 */
    if (geometryType === 'Point') {
      // 点样式：红色圆形，半径5
      style = new Style({
        image: new CircleStyle({
          radius: 5,
          fill: new Fill({
            color: 'rgba(255, 0, 0, 0.8)'
          }),
          stroke: new Stroke({
            color: '#ff0000',
            width: 2
          })
        }),
        text: createLabel(feature, { offsetY: -18 })
      });
    } else if (geometryType === 'LineString' || geometryType === 'MultiLineString') {
      // 线样式：黄色线条，宽度2
      style = new Style({
        stroke: new Stroke({
          color: '#ffff00',
          width: 2
        }),
        text: createLabel(feature, { placement: 'line' })
      });
    } else if (geometryType === 'Polygon' || geometryType === 'MultiPolygon') {
      // 面样式：蓝色填充，黄色边框
      style = new Style({
        fill: new Fill({
          color: 'rgba(0, 0, 255, 0.3)'
        }),
        stroke: new Stroke({
          color: '#ffff00',
          width: 2
        }),
        text: createLabel(feature)
      });
    } else if (geometryType === 'Circle') {
      // 圆形样式：蓝色填充，黄色边框
      style = new Style({
        fill: new Fill({
          color: 'rgba(0, 0, 255, 0.3)'
        }),
        stroke: new Stroke({
          color: '#ffff00',
          width: 2
        }),
        text: createLabel(feature)
      });
    }
    /* E */

    return style;
  };
}

/**
 * 开始绘制
 * 根据传入的几何类型创建对应的Draw interaction
 * @param {String} type - 绘制类型：'Point' | 'LineString' | 'Polygon' | 'Circle'
 */
const startDraw = (type) => {
  /* B 参数验证 */
  if (!type || !map) {
    console.warn('startDraw: 参数无效或地图未初始化');
    return;
  }
  /* E */

  /* B 停止之前的绘制 */
  stopDraw();
  /* E */

  /* B 创建绘制交互 */
  currentDraw = new Draw({
    source: drawSource,
    type: type,
    style: getDrawStyle() // 绘制过程中的样式
  });

  /* B 监听绘制完成事件 */
  currentDraw.on('drawend', (event) => {
    const feature = event.feature;
    const geometry = feature.getGeometry();

    /* B 将几何图形转换为GeoJSON格式（EPSG:4326） */
    const geoJSONFormat = new GeoJSON({
      dataProjection: 'EPSG:4326',
      featureProjection: 'EPSG:3857'
    });

    let geojson = null;

    /* B 处理Circle类型：转换为Polygon（圆形多边形） */
    if (geometry.getType() === 'Circle') {
      // Circle需要转换为Polygon格式
      // 使用Polygon.fromCircle将圆转换为多边形
      const polygonGeom = Polygon.fromCircle(geometry, 64);
      const polygonJSON = geoJSONFormat.writeGeometry(polygonGeom);
      const polygonObj = JSON.parse(polygonJSON);
      geojson = polygonObj;
    } else {
      // 其他类型直接转换
      const featureJSON = geoJSONFormat.writeFeature(feature);
      const featureObj = JSON.parse(featureJSON);
      geojson = featureObj.geometry;
    }
    /* E */

    /* B 绘制完成后，将临时feature移除，等待父组件回传数据后统一渲染 */
    if (drawSource && feature) {
      drawSource.removeFeature(feature);
    }

    /* B 通过emit将GeoJSON数据传递给父组件 */
    emit('geometryDraw', {
      type: type,
      geojson: geojson
    });
    /* E */
  });
  /* E */

  /* B 将绘制交互添加到地图 */
  map.addInteraction(currentDraw);
  /* E */
}

/**
 * 停止绘制
 * 移除当前的Draw interaction
 */
const stopDraw = () => {
  if (currentDraw && map) {
    map.removeInteraction(currentDraw);
    currentDraw = null;
  }
}

/**
 * 删除绘制的几何图形
 * 根据索引从绘制图层中删除对应的feature
 * @param {Number} index - geometryDataList中的索引
 */
const deleteDrawFeature = (index) => {
  if (!drawSource) {
    return;
  }

  /* B 查找对应的feature并删除 */
  const features = drawSource.getFeatures();
  // 由于绘制顺序与列表顺序一致，可以直接通过索引删除
  if (index >= 0 && index < features.length) {
    drawSource.removeFeature(features[index]);
  }
  /* E */
}

/**
 * 清除所有绘制的几何图形
 * 清空绘制图层中的所有feature
 */
const clearAllDrawFeatures = () => {
  if (drawSource) {
    drawSource.clear();
  }
}

/**
 * 回显绘制的几何图形
 * 将geometryDataList中的数据重新绘制到地图上
 * @param {Array} geometryDataList - 几何数据列表
 */
const renderDrawFeatures = (geometryDataList = []) => {
  if (!drawSource) {
    return;
  }

  /* B 清空现有绘制 */
  clearAllDrawFeatures();
  /* E */

  if (!Array.isArray(geometryDataList) || geometryDataList.length === 0) {
    return;
  }

  /* B 遍历数据列表，将每个几何图形添加到绘制图层 */
  const geoJSONFormat = new GeoJSON({
    dataProjection: 'EPSG:4326',
    featureProjection: 'EPSG:3857'
  });

  geometryDataList.forEach((item) => {
    if (item && item.geojson) {
      try {
        const geometry = geoJSONFormat.readGeometry(item.geojson, {
          dataProjection: 'EPSG:4326',
          featureProjection: 'EPSG:3857'
        });
        const feature = new Feature({
          geometry: geometry
        });
        feature.set('name', item.name || '');
        drawSource.addFeature(feature);
      } catch (error) {
        console.error('回显绘制图形失败:', error, item);
      }
    }
  });
  /* E */
}

/* E ============================================ 绘制功能相关方法结束 ============================================ */

onMounted(() => {
  areaId = JSON.parse(window.sessionStorage.getItem('usermsg')).areaId;
  getarea();

})
defineExpose({
  previewshape, 
  delIlayer, 
  locationM,
  /* B 暴露绘制相关方法给父组件 */
  startDraw,
  stopDraw,
  deleteDrawFeature,
  clearAllDrawFeatures,
  renderDrawFeatures
  /* E */
})
</script>
<template>
  <div id="map">
    <div class="map-menu">
      <div>
        <img :src="l1" @click.stop="SwitchLayers(1)" alt="" />
        <div class="mm-layers" v-if="lw == 1">
          <el-radio-group v-model="radio">
            <el-radio
              v-for="i in base"
              :key="i.id"
              :label="i.name"
              @change="addXYZ('baseLayer', i.layerUrl)"
              >{{ i.name }}</el-radio
            >
          </el-radio-group>
        </div>
      </div>
      <div>
        <img :src="l2" @click.stop="SwitchLayers(2)" alt="" />
        <div class="mm-layers" v-if="lw == 2">
          <el-checkbox-group v-model="checkList">
            <el-checkbox
              v-for="i in other"
              :key="i.id"
              @change="drawWMS(i.id, i.layerUrl, i.layerName, i.styleId, i.cql)"
              :label="i.name"
            />
          </el-checkbox-group>
        </div>
      </div>
    </div>
  </div>
</template>
<style scoped>
#map {
  width: 100%;
  height: 100%;
  position: relative;
}

.map-menu {
  display: flex;
  align-items: center;
  position: absolute;
  top: 16px;
  left: 16px;
  z-index: 22;
  /* overflow: hidden; */
  cursor: pointer;
}

.map-menu > div {
  width: 40px;
  height: 40px;
  margin-left: 16px;
  position: relative;
}

.map-menu > div img {
  width: 100%;
  height: 100%;
}

.mm-layers {
  padding: 20px 0 20px 20px;
  background-color: #ffffff;
  border-radius: 4px;
  position: absolute;
  top: 52px;
  left: 0;
  z-index: 2;
  /* overflow: hidden; */
}

.mm-layers::before {
  content: "";
  position: absolute;
  top: -10px;
  left: 20px;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 12px solid transparent;
  border-right: 12px solid transparent;
  border-bottom: 12px solid #ffffff;
}
</style>

<style>
.ol-popup {
  width: 450px;
  /* height: 4.6rem; */
  padding: 0 16px;
  position: absolute;
  bottom: 12px;
  left: -50px;
  background-color: white;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
  padding: 15px;
  border-radius: 10px;
  border: 1px solid #cccccc;
}

.ol-popup:after,
.ol-popup:before {
  top: 100%;
  border: solid transparent;
  content: " ";
  height: 0;
  width: 0;
  position: absolute;
  pointer-events: none;
}

.ol-popup:after {
  border-top-color: white;
  border-width: 10px;
  left: 48px;
  margin-left: -10px;
}

.ol-popup:before {
  border-top-color: #cccccc;
  border-width: 11px;
  left: 48px;
  margin-left: -11px;
}

.d-lkb-c {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
  cursor: pointer;
}

.popup-img {
  width: 100%;
  height: 300px;
  background-color: #000;
  display: flex;
  align-items: center;
  justify-content: center;
}

.popup-img img {
  width: 100%;
  height: 100%;
}

.popup-img video {
  width: 100%;
  height: 100%;
}
</style>